package fr.laas.knxinterface.communication;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Allows to receive orders from the gateway
 * 
 * @author Guillaume Garzone
 * 
 */
public class RxSocket extends Thread {
	/*
	 * 1) recoit une instruction (read/write) 2) apelle la bonne commande 3)
	 * envoie la commande sur le bus
	 */

	// port to listen to, default value 10081
	private int port;

	// allows to stop the thread if running
	private boolean running = false;
	// to launch the server
	private ServerSocket socketServeur = null;
	// socket to connect to the client
	private Socket socketClient = null;
	// to receive data
	private BufferedReader in = null;
	private MessageHandler handler = new MessageHandler();

	/**
	 * Constructor
	 * 
	 * @param port
	 */
	public RxSocket(int port) {
		this.port = port;
		this.handler.start();
	}

	// /**
	// * Constructor
	// */
	// public RxSocket() {
	// this.handler.start();
	// }

	/**
	 * Initializes the connection - server side
	 * 
	 * @return true if success
	 */
	private boolean initServer() {

		boolean result = false;

		try {
			socketServeur = new ServerSocket(port);
			System.out.println("Server launched");
			result = true;
		} catch (IOException e) {
			System.err.println("ERROR while launching the server");
			e.printStackTrace();
			this.stopServer();
		} catch (IllegalArgumentException i) {
			System.err.println("ERROR port number out of range");
			i.printStackTrace();
		}
		return result;

	}

	/**
	 * Accepts a connection
	 * 
	 * @return true if success
	 */
	private boolean acceptConnection() {

		boolean result = false;

		try {

			this.socketClient = this.socketServeur.accept();
			this.in = new BufferedReader(new InputStreamReader(
					this.socketClient.getInputStream()));

			result = true;
			System.out.println("Connected to : "
					+ this.socketClient.getInetAddress());

		} catch (IOException e) {

			System.err.println("ERROR while accepting connection");
			e.printStackTrace();
			this.closeConnectionClient();

		}
		return result;
	}

	/**
	 * Closes the connection with the client - closes the socket
	 */
	public void closeConnectionClient() {

		if (this.socketClient != null) {
			try {
				this.socketClient.close();
				System.out.println("RECEIVER : Connection closed");

			} catch (IOException e) {
				System.err.println("ERROR while closing connection");
				e.printStackTrace();
			}
		}
	}

	/**
	 * Stops the server
	 */
	public void stopServer() {

		if (this.socketServeur == null) {
			System.err.println("Socket Server was not opened");
		} else {
			try {
				this.socketServeur.close();
			} catch (IOException e) {
				System.err.println("ERROR while closing the server");
				e.printStackTrace();
			}
		}
		this.stopThread();
		if (this.handler != null) {
			this.handler.stopHandler();
		}
	}

	/**
	 * Stops the thread if the thread is running, calling stopServer stops all
	 * the service properly
	 */
	public void stopThread() {
		this.running = false;
	}

	/**
	 * Allows to open server side and listen to the appropriate socket
	 */
	@Override
	public void run() {

		String message = null;

		this.running = true;

		if (!this.initServer()) {
			this.running = false;
		} else {
			if (!this.acceptConnection()) {
				this.running = false;
			}
		}

		while (this.running) {

			try {
				message = in.readLine();
				if (message == null) {
					this.running = false;
				} else {
					System.out.println("SERVER receibed : " + message);

					this.handler.addMessageBuffer(message);

				}
			} catch (IOException e) {
				System.err.println("ERROR while reading the message");
				e.printStackTrace();
				this.closeConnectionClient();
			}
		}

		// CHECK if another method or enough to stop the server from here
		this.stopServer();
	}

}
